﻿/**
 * @file MessageClient.hpp
 * @brief SSD仿真系统IPC消息客户端类，负责与消息服务器进行通信。
 */
#pragma once
#ifndef __MessageClient_h__
#define __MessageClient_h__

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/deque.hpp>

#include "BasicTypes.h"
#include "MessageBaseService.hpp"

using namespace boost::interprocess;

/**
 * @class MessageClient
 * @brief IPC消息客户端类模板，负责与消息服务器进行通信。
 * @tparam TData 消息数据类型
 */
template <typename TData>
class MessageClient : public MessageBaseService<TData>
{
public:
    /**
     * @brief 构造函数，连接到指定名称的消息服务器。
     * @param serverName 服务器名称
     * @throws const char* 服务器不存在时抛出异常
     */
    MessageClient(const char *serverName)
    {
        managed_shared_memory *sharedMemory;
        try
        {
            sharedMemory = new managed_shared_memory(open_only, serverName);
        }
        catch (...)
        {
            throw "Server does not exist";
        }

        MessageBaseService<TData>::_ManagedShm = std::unique_ptr<managed_shared_memory>(sharedMemory);
        MessageBaseService<TData>::_Counter = MessageBaseService<TData>::_ManagedShm->find<MessageId>(COUNTER).first;
        MessageBaseService<TData>::_Queue = MessageBaseService<TData>::_ManagedShm->find<MessageQueue>(QUEUE).first;
        MessageBaseService<TData>::_ResponseQueue = MessageBaseService<TData>::_ManagedShm->find<MessageQueue>(RESPONSE_QUEUE).first;
    }

    /**
     * @brief 析构函数。
     */
    ~MessageClient()
    {
    }

    /**
     * @brief 分配新的消息对象。
     * @param payloadSize 载荷大小（默认0）
     * @param expectsResponse 是否需要响应（默认false）
     * @return 新分配的消息指针
     */
    Message<TData> *AllocateMessage(const U32 &payloadSize = 0, const bool &expectsResponse = false)
    {
        return MessageBaseService<TData>::DoAllocateMessage(payloadSize, expectsResponse);
    }

    /**
     * @brief 推送消息到服务器队列。
     * @param message 消息指针
     */
    void Push(Message<TData> *message)
    {
        message->_SubmitTime = std::chrono::high_resolution_clock::now();
        MessageBaseService<TData>::DoPush(MessageBaseService<TData>::_Queue, message);
    }

    /**
     * @brief 检查是否有响应消息。
     * @return 是否有响应
     */
    bool HasResponse()
    {
        return !MessageBaseService<TData>::_ResponseQueue->empty();
    }

    /**
     * @brief 弹出响应消息。
     * @return 响应消息指针
     */
    Message<TData> *PopResponse()
    {
        return MessageBaseService<TData>::DoPop(MessageBaseService<TData>::_ResponseQueue);
    }

    /**
     * @brief 释放消息对象及其载荷。
     * @param message 要释放的消息指针
     */
    void DeallocateMessage(Message<TData> *message)
    {
        MessageBaseService<TData>::DoDeallocateMessage(message);
    }

    /**
     * @brief 根据消息ID查找消息。
     * @param id 消息ID
     * @return 消息指针
     */
    Message<TData> *GetMessage(const MessageId &id)
    {
        return MessageBaseService<TData>::GetMessage(id);
    }
};

#endif